----------------------------------------------------------------------------------
-- Company:        Johns Hopkins University
-- Engineer:       Kevin Green
-- 
-- Create Date:    18:18:10 12/02/2011 
-- Design Name:    valid_move_gen
-- Module Name:    valid_move_gen - RTL 
-- Project Name:   top_gillis_green
-- Target Devices: 
-- Tool versions: 
-- Description:    This is the valid move generator.  This module generates a 
--                 vector with the possible valid moves given the num input.  
--                 Primarily this is used to interate through the tables
--                 to see if there are any valid moves given the current
--                 state of the bitboards
--
-- Dependencies:   lut7
--                 lut_8
--                 lut_6
--                 lut_5
--                 lut_4
--                 lut_3
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.game_logic_pkg.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity valid_move_gen is
	port( clk50      : in  std_logic;
			reset      : in  std_logic;
			w_bitboard : in  board;
			b_bitboard : in  board;
			player     : in  std_logic;
			sel        : in  std_logic_vector(1 downto 0);
			num        : in  std_logic_vector(2 downto 0);
			data_out   : out std_logic_vector(7 downto 0));
end valid_move_gen;

architecture RTL of valid_move_gen is

signal data_out_3 : std_logic_vector(7 downto 0);
signal data_out_4_0 : std_logic_vector(7 downto 0);
signal data_out_4_1 : std_logic_vector(7 downto 0);
signal data_out_5 : std_logic_vector(7 downto 0);
signal data_out_6 : std_logic_vector(7 downto 0);
signal data_out_7 : std_logic_vector(7 downto 0);
signal data_out_8 : std_logic_vector(7 downto 0);

signal black_3 : std_logic_vector(7 downto 0);
signal white_3 : std_logic_vector(7 downto 0);
signal black_4_0 : std_logic_vector(7 downto 0);
signal white_4_0: std_logic_vector(7 downto 0);
signal black_4_1 : std_logic_vector(7 downto 0);
signal white_4_1: std_logic_vector(7 downto 0);
signal black_5 : std_logic_vector(7 downto 0);
signal white_5 : std_logic_vector(7 downto 0);
signal black_6 : std_logic_vector(7 downto 0);
signal white_6 : std_logic_vector(7 downto 0);
signal black_7 : std_logic_vector(7 downto 0);
signal white_7 : std_logic_vector(7 downto 0);
signal black_8 : std_logic_vector(7 downto 0);
signal white_8 : std_logic_vector(7 downto 0);

signal t_player : std_logic;

begin

-- output mapping
process(clk50, reset) is
	variable u_temp : unsigned(2 downto 0);
begin
	if(reset = '1') then
		data_out <= (others => '0');
	elsif(rising_edge(clk50)) then
		case sel is
			when "00" => 
				data_out <= data_out_8;
			when "01" =>
				data_out <= data_out_8;
			when "10" => --a1 h8
				
				case num is
					when "111" => data_out <= '0' & data_out_7(6 downto 0);
					when "110" => data_out <= "00" & data_out_6(5 downto 0);
					when "101" => data_out <= data_out_3(2 downto 0) & data_out_5(4 downto 0);
					when "100" => data_out <= data_out_4_1(3 downto 0) & data_out_4_0(3 downto 0);
					when "011" => data_out <= data_out_5(4 downto 0) & data_out_3(2 downto 0);
					when "010" => data_out <= data_out_6(5 downto 0) & "00";
					when "001" => data_out <= data_out_7(6 downto 0) & '0';
					when others => data_out <= data_out_8;
				end case;
			when others => --a8 h1
				
				case num is
					when "111" => data_out <= data_out_8;
					when "110" => data_out <= data_out_7(6 downto 0) & '0';
					when "101" => data_out <= data_out_6(5 downto 0) & "00";
					when "100" => data_out <= data_out_5(4 downto 0) & data_out_3(2 downto 0);
					when "011" => data_out <= data_out_4_1(3 downto 0) & data_out_4_0(3 downto 0);
					when "010" => data_out <= data_out_3(2 downto 0) & data_out_5(4 downto 0);
					when "001" => data_out <= "00" & data_out_6(5 downto 0);
					when others => data_out <= '0' & data_out_7(6 downto 0);
				end case;
		end case;
	end if;
end process;

-- input mapping
process(clk50, reset) is
	variable u_row : unsigned(2 downto 0);
	variable u_col : unsigned(2 downto 0);
	variable u_temp : unsigned(2 downto 0);
	variable u_move : std_logic_vector(7 downto 0);
	variable t_black : std_logic_vector(7 downto 0);
	variable t_white : std_logic_vector(7 downto 0);
begin
	if(reset = '1') then
		black_3 <= (others => '0');
		white_3 <= (others => '0');
		black_4_0 <= (others => '0');
		white_4_0 <= (others => '0');
		black_4_1 <= (others => '0');
		white_4_1 <= (others => '0');
		black_5 <= (others => '0');
		white_5 <= (others => '0');
		black_6 <= (others => '0');
		white_6 <= (others => '0');
		black_7 <= (others => '0');
		white_7 <= (others => '0');
		black_8 <= (others => '0');
		white_8 <= (others => '0');
				
		t_player <= '0';
		
	elsif(rising_edge(clk50)) then		
		t_player <= player;		
		case sel is
			when "00" =>
				--standard
				black_8 <= b_bitboard(to_integer(unsigned(num)));
				white_8 <= w_bitboard(to_integer(unsigned(num)));
				
			when "01" =>
				--flipped
				black_8 <= b_bitboard(7)(to_integer(unsigned(num))) & 
							b_bitboard(6)(to_integer(unsigned(num))) & 
							b_bitboard(5)(to_integer(unsigned(num))) & 
							b_bitboard(4)(to_integer(unsigned(num))) & 
							b_bitboard(3)(to_integer(unsigned(num))) & 
							b_bitboard(2)(to_integer(unsigned(num))) & 
							b_bitboard(1)(to_integer(unsigned(num))) & 
							b_bitboard(0)(to_integer(unsigned(num))); 
							 
				white_8 <= w_bitboard(7)(to_integer(unsigned(num))) & 
							w_bitboard(6)(to_integer(unsigned(num))) & 
							w_bitboard(5)(to_integer(unsigned(num))) & 
							w_bitboard(4)(to_integer(unsigned(num))) & 
							w_bitboard(3)(to_integer(unsigned(num))) & 
							w_bitboard(2)(to_integer(unsigned(num))) & 
							w_bitboard(1)(to_integer(unsigned(num))) & 
							w_bitboard(0)(to_integer(unsigned(num))); 
							
			when "10" =>
				--a1 h8
				u_temp := unsigned(num);
				t_black := b_bitboard(to_integer(u_temp))(7) &
							b_bitboard(to_integer(u_temp+1))(6) &
							b_bitboard(to_integer(u_temp+2))(5) &
							b_bitboard(to_integer(u_temp+3))(4) &
							b_bitboard(to_integer(u_temp+4))(3) &
							b_bitboard(to_integer(u_temp+5))(2) &
							b_bitboard(to_integer(u_temp+6))(1) &
							b_bitboard(to_integer(u_temp+7))(0);
				
				t_white := w_bitboard(to_integer(u_temp))(7) &
							w_bitboard(to_integer(u_temp+1))(6) &
							w_bitboard(to_integer(u_temp+2))(5) &
							w_bitboard(to_integer(u_temp+3))(4) &
							w_bitboard(to_integer(u_temp+4))(3) &
							w_bitboard(to_integer(u_temp+5))(2) &
							w_bitboard(to_integer(u_temp+6))(1) &
							w_bitboard(to_integer(u_temp+7))(0);
							
				case u_temp is
					when "111" => 
						black_7 <= '0' & t_black(6 downto 0);
						white_7 <= '0' & t_white(6 downto 0);
					when "110" => 
						black_6 <= "00" & t_black(5 downto 0);
						white_6 <= "00" & t_white(5 downto 0);
					when "101" => 
						black_3 <= "00000" & t_black(7 downto 5);
						white_3 <= "00000" & t_white(7 downto 5);
						black_5 <= "000" & t_black(4 downto 0);
						white_5 <= "000" & t_white(4 downto 0);
					when "100" => 
						black_4_1 <= "0000" & t_black(7 downto 4);
						white_4_1 <= "0000" & t_white(7 downto 4);
						black_4_0 <= "0000" & t_black(3 downto 0);
						white_4_0 <= "0000" & t_white(3 downto 0);
					when "011" => 
						black_5 <= "000" & t_black(7 downto 3);
						white_5 <= "000" & t_white(7 downto 3);
						black_3 <= "00000" & t_black(2 downto 0);
						white_3 <= "00000" & t_white(2 downto 0);	
					when "010" => 
						black_6 <= "00" & t_black(7 downto 2);
						white_6 <= "00" & t_white(7 downto 2);
					when "001" => 
						black_7 <= "0" & t_black(7 downto 1);
						white_7 <= "0" & t_white(7 downto 1);
					when others => 
						black_8 <= t_black(7 downto 0);
						white_8 <= t_white(7 downto 0);
				end case;
			when others =>
				--a8 h1
				u_temp := unsigned(num);	
				t_black := b_bitboard(to_integer(u_temp))(7) &
							b_bitboard(to_integer(u_temp-1))(6) &
							b_bitboard(to_integer(u_temp-2))(5) &
							b_bitboard(to_integer(u_temp-3))(4) &
							b_bitboard(to_integer(u_temp-4))(3) &
							b_bitboard(to_integer(u_temp-5))(2) &
							b_bitboard(to_integer(u_temp-6))(1) &
							b_bitboard(to_integer(u_temp-7))(0);
				
				t_white := w_bitboard(to_integer(u_temp))(7) &
							w_bitboard(to_integer(u_temp-1))(6) &
							w_bitboard(to_integer(u_temp-2))(5) &
							w_bitboard(to_integer(u_temp-3))(4) &
							w_bitboard(to_integer(u_temp-4))(3) &
							w_bitboard(to_integer(u_temp-5))(2) &
							w_bitboard(to_integer(u_temp-6))(1) &
							w_bitboard(to_integer(u_temp-7))(0);
				case u_temp is
					when "111" => 
						black_8 <= t_black(7 downto 0);
						white_8 <= t_white(7 downto 0);
					when "110" => 
						black_7 <= "0" & t_black(7 downto 1);
						white_7 <= "0" & t_white(7 downto 1);
					when "101" => 
						black_6 <= "00" & t_black(7 downto 2);
						white_6 <= "00" & t_white(7 downto 2);
					when "100" => 
						black_5 <= "000" & t_black(7 downto 3);
						white_5 <= "000" & t_white(7 downto 3);
						black_3 <= "00000" & t_black(2 downto 0);
						white_3 <= "00000" & t_white(2 downto 0 );
					when "011" =>
						black_4_1 <= "0000" & t_black(7 downto 4);
						white_4_1 <= "0000" & t_white(7 downto 4);
						black_4_0 <= "0000" & t_black(3 downto 0);
						white_4_0 <= "0000" & t_white(3 downto 0);				
					when "010" => 
						black_3 <= "00000" & t_black(7 downto 5);
						white_3 <= "00000" & t_white(7 downto 5);
						black_5 <= "000" & t_black(4 downto 0);
						white_5 <= "000" & t_white(4 downto 0);
					when "001" => 
						black_6 <= "00" & t_black(5 downto 0);
						white_6 <= "00" & t_white(5 downto 0);
					when others => 
						black_7 <= '0' & t_black(6 downto 0);
						white_7 <= '0' & t_white(6 downto 0);
				end case;
		end case;
	end if;
end process;

U_lut_3 : entity work.lut_3
	port map(player => t_player,
				black => black_3,
				white => white_3,
				data_out => data_out_3);

U_lut_4_0 : entity work.lut_4
	port map(player => t_player,
				black => black_4_0,
				white => white_4_0,
				data_out => data_out_4_0);
				
U_lut_4_1 : entity work.lut_4
	port map(player => t_player,
				black => black_4_1,
				white => white_4_1,
				data_out => data_out_4_1);

U_lut_5 : entity work.lut_5
	port map(player => t_player,
				black => black_5,
				white => white_5,
				data_out => data_out_5);

U_lut_6 : entity work.lut_6
	port map(player => t_player,
				black => black_6,
				white => white_6,
				data_out => data_out_6);

U_lut7 : entity work.lut7
	port map(player => player,
				black => black_7,
				white => white_7,
				data_out => data_out_7);
				
U_lut_8 : entity work.lut_8
	port map(player => player,
				black => black_8,
				white => white_8,
				data_out => data_out_8);

end RTL;

